import { useState, useEffect } from 'react'

const STORAGE_KEY = 'weight_tracker_data'

const MOCK_DATA = [
  { date: '2024-11-01', weight: 72.5 },
  { date: '2024-11-03', weight: 72.1 },
  { date: '2024-11-05', weight: 71.8 }
]

const API_BASE = '/api/weights'

function recordToLocal(rec) {
  // Convert server record to local format { id, date, weight, created_at }
  const created = rec.created_at || rec.createdAt || rec.created
  const date = created ? created.split('T')[0] : (rec.date || '')
  return { id: rec.id, date, weight: rec.weight, created_at: created, raw: rec }
}

async function fetchWeightsFromServer(limit = 500, offset = 0) {
  try {
    const res = await fetch(`${API_BASE}?limit=${limit}&offset=${offset}`)
    if (!res.ok) throw new Error(`Status ${res.status}`)
    const body = await res.json()
    // Expected structure: { code:200, message:'', data: { records: [...] }, success:true }
    if (body && body.data && Array.isArray(body.data.records)) {
      return body.data.records.map(recordToLocal)
    }
    return []
  } catch (e) {
    console.error('Failed to fetch weights from server', e)
    return null
  }
}

async function sendWeightToServer(method, payload) {
  try {
    const res = await fetch(API_BASE, {
      method,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload)
    })
    if (!res.ok) {
      // try to parse error body
      const errBody = await res.text().catch(()=>null)
      throw new Error(`Status ${res.status} ${errBody || ''}`)
    }
    const body = await res.json().catch(()=>null)
    return body
  } catch (e) {
    console.error(`Failed to ${method} weight`, e)
    return null
  }
}

export function useWeightData() {
  const [weights, setWeights] = useState([])
  const [isLoaded, setIsLoaded] = useState(false)

  useEffect(() => {
    let mounted = true
    ;(async () => {
      // try server first
      const serverData = await fetchWeightsFromServer(500, 0)
      if (!mounted) return
      if (serverData === null) {
        // network failed -> fallback to localStorage
        try {
          const stored = localStorage.getItem(STORAGE_KEY)
          if (stored) {
            const parsed = JSON.parse(stored)
            setWeights(Array.isArray(parsed) ? parsed : MOCK_DATA)
          } else {
            setWeights(MOCK_DATA)
            localStorage.setItem(STORAGE_KEY, JSON.stringify(MOCK_DATA))
          }
        } catch (e) {
          console.error('Failed to load weight data', e)
          setWeights(MOCK_DATA)
        }
      } else {
        // serverData already converted to local shape via recordToLocal
        setWeights(serverData)
        try { localStorage.setItem(STORAGE_KEY, JSON.stringify(serverData)) } catch(e){ console.error(e) }
      }
      setIsLoaded(true)
    })()

    return () => { mounted = false }
  }, [])

  const persistLocal = (next) => {
    try { localStorage.setItem(STORAGE_KEY, JSON.stringify(next)) } catch(e){ console.error(e) }
  }

  const addWeight = async (weight) => {
    const today = new Date().toISOString().split('T')[0]
    setWeights(prev => {
      const existingIndex = prev.findIndex(w => w.date === today)
      let updated
      if (existingIndex >= 0) {
        updated = [...prev]
        updated[existingIndex] = { ...updated[existingIndex], weight }
      } else {
        updated = [...prev, { date: today, weight }]
      }
      persistLocal(updated)
      return updated
    })

    // Optimistic local update, then try server
    const payload = { date: today, weight }
    // if exists on server we send PUT, otherwise POST — we can't be 100% sure, so try POST then fallback to PUT
    let result = await sendWeightToServer('POST', payload)
    if (result === null) {
      // network failure — already persisted locally
      return null
    }
    // result expected: { code, message, data:{ records: [...] }, success }
    if (result && result.success) {
      // server returned created/updated records — pick first if present
      const rec = result.data && Array.isArray(result.data.records) && result.data.records[0]
      if (rec) {
        const local = recordToLocal(rec)
        // replace local item for that date with server record (adds id/created_at)
        setWeights(prev => {
          const idx = prev.findIndex(w => w.date === local.date)
          if (idx >= 0) {
            const updated = [...prev]
            updated[idx] = { ...updated[idx], ...local }
            persistLocal(updated)
            return updated
          } else {
            const updated = [...prev, local]
            persistLocal(updated)
            return updated
          }
        })
      }
      return result
    }

    // if server returned non-success and code indicates conflict, try update
    if (result && result.code === 409) {
      const upd = await sendWeightToServer('PUT', payload)
      if (upd && upd.success) {
        const rec = upd.data && Array.isArray(upd.data.records) && upd.data.records[0]
        if (rec) {
          const local = recordToLocal(rec)
          setWeights(prev => {
            const idx = prev.findIndex(w => w.date === local.date)
            if (idx >= 0) {
              const updated = [...prev]
              updated[idx] = { ...updated[idx], ...local }
              persistLocal(updated)
              return updated
            }
            const updated = [...prev, local]
            persistLocal(updated)
            return updated
          })
        }
      }
      return upd || result
    }

    // other non-success responses
    return result
  }

  const getTodayWeight = () => {
    const today = new Date().toISOString().split('T')[0]
    return weights.find(w => w.date === today)?.weight || null
  }

  const getWeightForDate = (date) => weights.find(w => w.date === date)?.weight || null

  const deleteWeight = async (date) => {
    setWeights(prev => {
      const updated = prev.filter(w => w.date !== date)
      persistLocal(updated)
      return updated
    })
    // attempt server delete
    const payload = { date }
    const res = await sendWeightToServer('DELETE', payload)
    if (res === null) {
      // network failure — already removed locally
      return null
    }
    // if server responded with success, keep local deletion; otherwise, consider reloading from server
    if (res && res.success) return res
    return res
  }

  const getStats = () => {
    if (weights.length === 0) return { min: 0, max: 0, avg: 0, count: 0, trend: 0 }
    const sorted = [...weights].sort((a,b)=>a.weight-b.weight)
    const sum = weights.reduce((acc,w)=>acc+w.weight,0)
    const latest = weights[weights.length-1].weight
    const earliest = weights[0].weight
    return { min: sorted[0].weight, max: sorted[sorted.length-1].weight, avg: sum/weights.length, count:weights.length, trend: latest - earliest }
  }

  return { weights, addWeight, getTodayWeight, getWeightForDate, deleteWeight, getStats, isLoaded }
}

export default useWeightData
